/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.vcs.cmdline.commands;
import org.netbeans.modules.vcs.cmdline.*;
import org.netbeans.modules.vcs.VcsFileSystem;
import org.netbeans.modules.vcs.util.*;
import org.netbeans.modules.vcs.cmdline.exec.*;
import java.util.*;
import java.io.*;
/**
*
* @author Martin Entlicher
* @version
*/
public class CvsLogInfo extends Object implements RegexListener {
private Debug E=new Debug("CvsLogInfo",true); // NOI18N
private Debug D=E;
private StringBuffer logBuffer = new StringBuffer(4096);
private Vector revisions = new Vector();
/**
* @associates String
*/
private Vector revisionsFile = new Vector();
private Vector branches = new Vector();
/**
* @associates String
*/
private Vector branchesFile = new Vector();
private Vector orderRevBranch = new Vector();
/**
* @associates Integer
*/
private Vector orderRevBranchFile = new Vector();
private static final int ORDER_REVISION = 0;
private static final int ORDER_BRANCH = 1;
/**
* Contains revision number as the key and the tag name as the value.
*/
private Hashtable symbolicNames = new Hashtable();
/**
* @associates String
*/
private Hashtable symbolicNamesFile = new Hashtable();
private boolean matchingSymbolicNames = false;
private boolean mergeIsEmpty = true;
private CvsRevisionGraph revisionGraph = null;
private String revisionStr = new String("revision"); // NOI18N
private String branchesStr = new String("branches"); // NOI18N
private String symbNamesStr = new String("symbolic names"); // NOI18N
private String nextFileStr = new String("=================="); // NOI18N
/** Creates new CvsLogInfo */
public CvsLogInfo() {
}
public Vector getRevisions() {
return revisions;
}
public Vector getBranches() {
return branches;
}
public Hashtable getSymbolicNames() {
return symbolicNames;
}
public Vector getRevisionsWithSymbolicNames() {
String revision;
Vector revisions = getRevisions();
Vector revSN = new Vector(revisions);
Hashtable sn = getSymbolicNames();
Enumeration enum = sn.keys();
while(enum.hasMoreElements()) {
revision = (String) enum.nextElement();
String symbName = (String) sn.get(revision);
D.deb("I have symbolic name: "+symbName+" for revision: "+revision); // NOI18N
int revIndex = revSN.indexOf(revision);
if (symbName != null) revision += " "+symbName; // NOI18N
if (revIndex >= 0) {
revSN.setElementAt(revision, revIndex);
} else {
revSN.addElement(revision);
}
}
return revSN;
}
public Vector getBranchesWithSymbolicNames() {
String revision;
Vector branches = getBranches();
Vector brSN = new Vector(branches);
Hashtable sn = getSymbolicNames();
Enumeration enum = sn.keys();
while(enum.hasMoreElements()) {
revision = (String) enum.nextElement();
String symbName = (String) sn.get(revision);
D.deb("I have symbolic name: "+symbName+" for revision: "+revision); // NOI18N
int brIndex = brSN.indexOf(revision);
if (brIndex >= 0) {
if (symbName != null) revision += " "+symbName; // NOI18N
brSN.setElementAt(revision, brIndex);
} else {
int lastDot = revision.lastIndexOf('.');
if (lastDot > 1 && revision.charAt(lastDot - 1) == '0' &&
revision.charAt(lastDot - 2) == '.') {
String branch = revision.substring(0, lastDot-1) + revision.substring(lastDot+1);
D.deb("I have created the branch number "+branch); // NOI18N
brIndex = brSN.indexOf(branch);
if (symbName != null) branch += " "+symbName; // NOI18N
if (brIndex >= 0) {
brSN.setElementAt(branch, brIndex);
} else {
brSN.addElement(branch);
}
}
}
}
return brSN;
}
public CvsRevisionGraph getRevisionGraph() {
return revisionGraph;
}
public boolean updateLogInfo(Hashtable vars, String[] args,
NoRegexListener stdoutListener,
NoRegexListener stderrListener) {
revisionGraph = new CvsRevisionGraph();
mergeIsEmpty = true;
String cmd = MiscStuff.array2string(args);
Variables v=new Variables();
String prepared=v.expand(vars,cmd, true);
D.deb("Log prepared: "+prepared); // NOI18N
if (stderrListener != null) stderrListener.match("LOG INFO: "+prepared); // NOI18N
ExternalCommand ec=new ExternalCommand(prepared);
ec.setTimeout(((Long) vars.get("TIMEOUT")).longValue()); // NOI18N
String logDataRegex = (String) vars.get("DATAREGEX"); // NOI18N
try{
D.deb("stdout log dataRegex = "+logDataRegex); // NOI18N
ec.addStdoutRegexListener(this, logDataRegex);
} catch (BadRegexException e) {
if (stderrListener != null) stderrListener.match("cvs log: Bad data regex "+logDataRegex+"\n"); // NOI18N
return false;
}
if (stdoutListener != null) ec.addStdoutNoRegexListener(stdoutListener);
if (stderrListener != null) ec.addStderrNoRegexListener(stderrListener);
if ( ec.exec() != ExternalCommand.SUCCESS ){
E.err("exec failed "+ec.getExitStatus()); // NOI18N
return false;
}
D.deb("branches = "+branches); // NOI18N
for(int i = 0; i < orderRevBranch.size(); i++) {
Integer what = (Integer) orderRevBranch.get(i);
i++;
if (what.intValue() == ORDER_REVISION) {
Integer revision = (Integer) orderRevBranch.get(i);
revisionGraph.insertRevision((String) revisions.get(revision.intValue()));
} else {
Integer branch = (Integer) orderRevBranch.get(i);
revisionGraph.insertBranch((String) branches.get(branch.intValue()));
}
}
//for(int i = 0; i < branches.size(); i++) revisionGraph.insertBranch((String) branches.get(i));
//for(int i = 0; i < revisions.size(); i++) revisionGraph.insertRevision((String) revisions.get(i));
return true;
}
/**
* Merge the common content of Hashtables <CODE>h1</CODE> and <CODE>h2</CODE> into <CODE>h1</CODE>.
* In other words it deletes every entry of <CODE>h1</CODE> which is not contained in <CODE>h2</CODE>.
* @param h1
* @param h2
*/
private void mergeCommonHashtable(Hashtable h1, Hashtable h2) {
Enumeration enum1 = h1.keys();
while (enum1.hasMoreElements()) {
Object o1 = enum1.nextElement();
boolean contains = false;
Enumeration enum2 = h2.keys();
while (enum2.hasMoreElements()) {
Object o2 = enum2.nextElement();
if (o1.equals(o2)) { contains = true; break; }
}
if (!contains) h1.remove(o1);
}
}
/**
* Merge the content of order vectors.
*/
private void mergeRevBr() {
for(int i = 0; i < orderRevBranch.size(); i++) {
Integer what = (Integer) orderRevBranch.get(i);
i++;
if (what.intValue() == ORDER_REVISION) {
Integer revision = (Integer) orderRevBranch.get(i);
String rev = (String) revisions.get(revision.intValue());
int j;
for(j = 0; j < orderRevBranchFile.size(); j++) {
Integer whatFile = (Integer) orderRevBranchFile.get(j);
j++;
if (whatFile.intValue() == ORDER_REVISION) {
Integer revisionFile = (Integer) orderRevBranchFile.get(j);
String revFile = (String) revisionsFile.get(revisionFile.intValue());
if (revFile.equals(rev)) break;
}
}
if (j >= orderRevBranchFile.size()) {
orderRevBranch.remove(i-1);
orderRevBranch.remove(i);
revisions.remove(revision.intValue());
i -= 2;
}
} else {
Integer branch = (Integer) orderRevBranch.get(i);
String br = (String) branches.get(branch.intValue());
int j;
for(j = 0; j < orderRevBranchFile.size(); j++) {
Integer whatFile = (Integer) orderRevBranchFile.get(j);
j++;
if (whatFile.intValue() == ORDER_REVISION) {
Integer branchFile = (Integer) orderRevBranchFile.get(j);
String brFile = (String) branchesFile.get(branchFile.intValue());
if (brFile.equals(br)) break;
}
}
if (j >= orderRevBranchFile.size()) {
orderRevBranch.remove(i-1);
orderRevBranch.remove(i);
branches.remove(branch.intValue());
i -= 2;
}
}
}
}
private void mergeCommonRevisions() {
if (mergeIsEmpty) {
revisions = new Vector(revisionsFile);
branches = new Vector(branchesFile);
symbolicNames = new Hashtable(symbolicNamesFile);
orderRevBranch = new Vector(orderRevBranchFile);
} else {
//mergeCommonVector(revisions, revisionsFile);
//mergeCommonVector(branches, branchesFile);
mergeCommonHashtable(symbolicNames, symbolicNamesFile);
mergeRevBr();
//orderRevBranch = new Vector(orderRevBranchFile);
}
mergeIsEmpty = false;
}
public void match(String[] elements) {
if (elements[0] == null) return;
D.deb("log match: "+elements[0]); // NOI18N
logBuffer.append(elements[0]+"\n"); // NOI18N
if (elements[0].indexOf(nextFileStr) >= 0) {
mergeCommonRevisions();
}
if (elements[0].indexOf(revisionStr) == 0) {
String revision = elements[0].substring(revisionStr.length(), elements[0].length()).trim();
revisionsFile.add(revision);
orderRevBranchFile.add(new Integer(ORDER_REVISION));
orderRevBranchFile.add(new Integer(revisionsFile.size() - 1));
//revisionGraph.insertRevision(revision);
}
if (elements[0].indexOf(branchesStr) >= 0) {
int bBegin = branchesStr.length()+1;
int bEnd = elements[0].indexOf(';', bBegin);
if (bEnd < 0) bEnd = elements[0].length();
while (bBegin < bEnd) {
String branch = elements[0].substring(bBegin, bEnd).trim();
branchesFile.add(branch);
orderRevBranchFile.add(new Integer(ORDER_BRANCH));
orderRevBranchFile.add(new Integer(branchesFile.size() - 1));
//revisionGraph.insertBranch(branch);
bBegin = bEnd+1;
bEnd = elements[0].indexOf(';', bBegin);
if (bEnd < 0) bEnd = elements[0].length();
}
}
if (matchingSymbolicNames) {
int keyIndex = 0;
while (elements[0].charAt(keyIndex) == ' ' || elements[0].charAt(keyIndex) == '\t') keyIndex++;
if (keyIndex == 0) matchingSymbolicNames = false;
else {
int valueIndex = keyIndex;
while (elements[0].charAt(valueIndex) != ':') valueIndex++;
/*
symbolicNames.put(elements[0].substring(keyIndex, valueIndex).trim(),
elements[0].substring(valueIndex + 1, elements[0].length()).trim());
*/
symbolicNamesFile.put(elements[0].substring(valueIndex + 1, elements[0].length()).trim(),
elements[0].substring(keyIndex, valueIndex).trim());
//D.deb("Putting to symbolic names: ("+elements[0].substring(valueIndex + 1, elements[0].length()).trim()+ // NOI18N
// ", "+elements[0].substring(keyIndex, valueIndex).trim()+")"); // NOI18N
}
}
if (elements[0].indexOf(symbNamesStr) >= 0) matchingSymbolicNames = true;
}
}